﻿
/**
************************************************************************************************************************
* @file    CPU.c
* @author  CTY
* @version 1.0
* @date    2018/10/18
* @brief   CPU
************************************************************************************************************************
@verbatim
    （详细内容）
@endverbatim
* 
************************************************************************************************************************
*/ 

/*====================================================================================================================*/
/*                                                      引用文件                                                      */
/*====================================================================================================================*/
#include "stm32h7xx_hal.h"


extern void CPU_FMC_Init(void);
extern void CPU_QSPI_Init(void);
/*====================================================================================================================*/
/*                                                      常量定义                                                      */
/*====================================================================================================================*/


/*====================================================================================================================*/
/*                                                     本地宏定义                                                     */
/*====================================================================================================================*/


/*====================================================================================================================*/
/*                                                  本地数据类型定义                                                  */
/*====================================================================================================================*/


/*====================================================================================================================*/
/*                                                      全局变量                                                      */
/*====================================================================================================================*/


/*====================================================================================================================*/
/*                                                      本地变量                                                      */
/*====================================================================================================================*/


/*====================================================================================================================*/
/*                                                    本地函数声明                                                    */
/*====================================================================================================================*/
static void _SystemClock_Config(void);
static void _MPU_Config(void);


/*====================================================================================================================*/
/*                                                      全局函数                                                      */
/*====================================================================================================================*/

/**************************************************************************************************/
/**
@brief      初始化
@verbatim   
    （详细描述）
@endverbatim
@param      无
@retval     true=成功，false=失败。
*/
/**************************************************************************************************/
void CPU_Init(void)
{
    _MPU_Config();
    SCB_EnableICache();
    SCB_EnableDCache();

    HAL_Init();
    _SystemClock_Config();
    
    __HAL_RCC_GPIOA_CLK_ENABLE();
    __HAL_RCC_GPIOB_CLK_ENABLE();
    __HAL_RCC_GPIOC_CLK_ENABLE();
    __HAL_RCC_GPIOD_CLK_ENABLE();
    __HAL_RCC_GPIOE_CLK_ENABLE();
    __HAL_RCC_GPIOF_CLK_ENABLE();
    __HAL_RCC_GPIOG_CLK_ENABLE();
    __HAL_RCC_GPIOH_CLK_ENABLE();
    __HAL_RCC_GPIOI_CLK_ENABLE();
    __HAL_RCC_GPIOJ_CLK_ENABLE();
    __HAL_RCC_GPIOK_CLK_ENABLE();
    __HAL_RCC_CRC_CLK_ENABLE();   // 启用CRC时钟，UI使用
    
    CPU_FMC_Init();
    CPU_QSPI_Init();
}

void SysTick_Handler(void)
{
    HAL_IncTick();
    HAL_SYSTICK_IRQHandler();
}


/*====================================================================================================================*/
/*                                                      本地函数                                                      */
/*====================================================================================================================*/
/**************************************************************************************************/
/**
@brief      初始化系统时钟
@verbatim   
    （详细注解）
@endverbatim
@param      无
@retval     无
*/
/**************************************************************************************************/
static void _SystemClock_Config(void)
{
    RCC_OscInitTypeDef RCC_OscInitStruct = { 0 };
    RCC_ClkInitTypeDef RCC_ClkInitStruct = { 0 };
    RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = { 0 };

    /** Supply configuration update enable 
    */
    HAL_PWREx_ConfigSupply(PWR_LDO_SUPPLY);
    /** Configure the main internal regulator output voltage 
    */
    __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);

    while (!__HAL_PWR_GET_FLAG(PWR_FLAG_VOSRDY)) {}
    /** Configure LSE Drive Capability 
    */
    HAL_PWR_EnableBkUpAccess();
    __HAL_RCC_LSEDRIVE_CONFIG(RCC_LSEDRIVE_LOW);
    /** Macro to configure the PLL clock source 
    */
    __HAL_RCC_PLL_PLLSOURCE_CONFIG(RCC_PLLSOURCE_HSE);
    /** Initializes the CPU, AHB and APB busses clocks 
    */
    RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI48 | RCC_OSCILLATORTYPE_HSE | RCC_OSCILLATORTYPE_LSE;
    RCC_OscInitStruct.HSEState = RCC_HSE_ON;
    RCC_OscInitStruct.LSEState = RCC_LSE_ON;
    RCC_OscInitStruct.HSI48State = RCC_HSI48_ON;
    RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
    RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
    RCC_OscInitStruct.PLL.PLLM = 5;
    RCC_OscInitStruct.PLL.PLLN = 192;
    RCC_OscInitStruct.PLL.PLLP = 2;
    RCC_OscInitStruct.PLL.PLLQ = 20;
    RCC_OscInitStruct.PLL.PLLR = 2;
    RCC_OscInitStruct.PLL.PLLRGE = RCC_PLL1VCIRANGE_2;
    RCC_OscInitStruct.PLL.PLLVCOSEL = RCC_PLL1VCOWIDE;
    RCC_OscInitStruct.PLL.PLLFRACN = 0;
    while (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) ;
    
    /** Initializes the CPU, AHB and APB busses clocks 
    */
    RCC_ClkInitStruct.ClockType = 
          RCC_CLOCKTYPE_HCLK 
        | RCC_CLOCKTYPE_SYSCLK 
        | RCC_CLOCKTYPE_PCLK1 
        | RCC_CLOCKTYPE_PCLK2 
        | RCC_CLOCKTYPE_D3PCLK1 
        | RCC_CLOCKTYPE_D1PCLK1;
    RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
    RCC_ClkInitStruct.SYSCLKDivider = RCC_SYSCLK_DIV1;
    RCC_ClkInitStruct.AHBCLKDivider = RCC_HCLK_DIV2;
    RCC_ClkInitStruct.APB3CLKDivider = RCC_APB3_DIV2;
    RCC_ClkInitStruct.APB1CLKDivider = RCC_APB1_DIV2;
    RCC_ClkInitStruct.APB2CLKDivider = RCC_APB2_DIV2;
    RCC_ClkInitStruct.APB4CLKDivider = RCC_APB4_DIV2;
    while ((HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4)) != HAL_OK) ;
    
    PeriphClkInitStruct.PeriphClockSelection = 
          RCC_PERIPHCLK_RTC 
        | RCC_PERIPHCLK_LTDC 
        | RCC_PERIPHCLK_FDCAN 
        | RCC_PERIPHCLK_USART1
        | RCC_PERIPHCLK_UART5 
        | RCC_PERIPHCLK_RNG 
        | RCC_PERIPHCLK_SPI1 
        | RCC_PERIPHCLK_ADC
        | RCC_PERIPHCLK_I2C1 
        | RCC_PERIPHCLK_USB 
        | RCC_PERIPHCLK_QSPI 
        | RCC_PERIPHCLK_FMC
        | RCC_PERIPHCLK_CKPER;
    PeriphClkInitStruct.PLL2.PLL2M = 5;
    PeriphClkInitStruct.PLL2.PLL2N = 160;
    PeriphClkInitStruct.PLL2.PLL2P = 10;
    PeriphClkInitStruct.PLL2.PLL2Q = 5;
    PeriphClkInitStruct.PLL2.PLL2R = 4;      // FMC: PLL2N / PLL2R
    PeriphClkInitStruct.PLL2.PLL2RGE = RCC_PLL2VCIRANGE_2;
    PeriphClkInitStruct.PLL2.PLL2VCOSEL = RCC_PLL2VCOWIDE;
    PeriphClkInitStruct.PLL2.PLL2FRACN = 0;
    PeriphClkInitStruct.PLL3.PLL3M = 25;
    PeriphClkInitStruct.PLL3.PLL3N = 192;
    PeriphClkInitStruct.PLL3.PLL3P = 2;
    PeriphClkInitStruct.PLL3.PLL3Q = 4;
    PeriphClkInitStruct.PLL3.PLL3R = 6;      // LTDC: PLL3N / PLL3R
    PeriphClkInitStruct.PLL3.PLL3RGE = RCC_PLL3VCIRANGE_0;
    PeriphClkInitStruct.PLL3.PLL3VCOSEL = RCC_PLL3VCOWIDE;
    PeriphClkInitStruct.PLL3.PLL3FRACN = 0;
    PeriphClkInitStruct.FmcClockSelection = RCC_FMCCLKSOURCE_PLL2;
    PeriphClkInitStruct.QspiClockSelection = RCC_QSPICLKSOURCE_D1HCLK;
    PeriphClkInitStruct.CkperClockSelection = RCC_CLKPSOURCE_HSI;
    PeriphClkInitStruct.Spi123ClockSelection = RCC_SPI123CLKSOURCE_PLL;
    PeriphClkInitStruct.FdcanClockSelection = RCC_FDCANCLKSOURCE_PLL;
    PeriphClkInitStruct.Usart234578ClockSelection = RCC_USART234578CLKSOURCE_D2PCLK1;
    PeriphClkInitStruct.Usart16ClockSelection = RCC_USART16CLKSOURCE_D2PCLK2;
    PeriphClkInitStruct.RngClockSelection = RCC_RNGCLKSOURCE_PLL;
    PeriphClkInitStruct.I2c123ClockSelection = RCC_I2C123CLKSOURCE_D2PCLK1;
    PeriphClkInitStruct.UsbClockSelection = RCC_USBCLKSOURCE_PLL;
    PeriphClkInitStruct.AdcClockSelection = RCC_ADCCLKSOURCE_CLKP;
    PeriphClkInitStruct.RTCClockSelection = RCC_RTCCLKSOURCE_LSE;
    while (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK) ;
    
    /** Enables the Clock Security System 
    */
    HAL_RCC_EnableCSS();
    /** Enables the Clock Security System 
    */
    HAL_RCCEx_EnableLSECSS();
    /** Enable USB Voltage detector 
    */
    HAL_PWREx_EnableUSBVoltageDetector();
}

/*
*********************************************************************************************************
*   函 数 名: MPU_Config
*   功能说明: 配置MPU
*   形    参: 无
*   返 回 值: 无
*********************************************************************************************************
*/
static void _MPU_Config( void )
{
    MPU_Region_InitTypeDef MPU_InitStruct;
    MPU_InitStruct.Enable           = MPU_REGION_ENABLE;
    MPU_InitStruct.SubRegionDisable = 0x00;
    MPU_InitStruct.TypeExtField     = MPU_TEX_LEVEL0;
    MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
    MPU_InitStruct.DisableExec      = MPU_INSTRUCTION_ACCESS_ENABLE;
    MPU_InitStruct.IsShareable      = MPU_ACCESS_NOT_SHAREABLE;
    MPU_InitStruct.IsCacheable      = MPU_ACCESS_NOT_CACHEABLE;
    MPU_InitStruct.IsBufferable     = MPU_ACCESS_NOT_BUFFERABLE;

    /* 禁止 MPU */
    HAL_MPU_Disable();
    
    /* 配置FMC扩展IO的MPU属性为Device或者Strongly Ordered */
    /* 不能用MPU_ACCESS_CACHEABLE; 会出现两次CS、WE信号 */
    MPU_InitStruct.Number           = MPU_REGION_NUMBER0;
    MPU_InitStruct.BaseAddress      = 0x60000000;
    MPU_InitStruct.Size             = ARM_MPU_REGION_SIZE_64KB;
    MPU_InitStruct.IsCacheable      = MPU_ACCESS_NOT_CACHEABLE;
    HAL_MPU_ConfigRegion(&MPU_InitStruct);

    /*
    配置SDRAM的MPU属性为Write through, read allocate，no write allocate
    这种配置的情况下，读Cache对性能提升有一定的作用，但使用GUI做Alpha的场合要注意。
    需要用户手动做无效化操作。
     */
    MPU_InitStruct.Number           = MPU_REGION_NUMBER1;
    MPU_InitStruct.BaseAddress      = 0xC0000000;
    MPU_InitStruct.Size             = MPU_REGION_SIZE_32MB;
    MPU_InitStruct.IsCacheable      = MPU_ACCESS_CACHEABLE;
    HAL_MPU_ConfigRegion(&MPU_InitStruct);

    /*使能 MPU */
    HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);
}


/*====================================================================================================================*/
/*                                                     End of file                                                    */
/*====================================================================================================================*/
